﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Drawing;

namespace MipsPipelineSimulator
{
    class WBStage
    {
        //能否运行
        static public int enableRun = 0;

        static private ManualResetEvent manuaEevent = new ManualResetEvent(false);

        static private Thread wbThread = null;

        static public Point[] position = new Point[12];

        static private MainForm mainForm = null;

        static public Code code;

        static public object[] args = null;

        static private void ThreadFun()
        {
            if (enableRun < 0)
            {
                IDStage.registerReadManualEvent.Set();
                IDStage.idDrawManualEvent.Set();
                manuaEevent.Set();
                return;
            }
             WBStage.enableRun--;

            string str1 = null;
            switch(code.codeType)
            {
                 case CodeType.ADD:
                 case CodeType.SUB:
                 case CodeType.MUL:
                 case CodeType.SLT:
                 case CodeType.AND:
                 case CodeType.NOR:
                 case CodeType.OR:
                 case CodeType.XOR:
                 case CodeType.SLLV:
                 case CodeType.SRAV:
                 case CodeType.SRLV:
                 case CodeType.ADDI:
                 case CodeType.SLTI:
                 case CodeType.ANDI:
                 case CodeType.ORI:
                 case CodeType.XORI:
                 case CodeType.SLL:
                 case CodeType.SRA:
                 case CodeType.SRL:
                     {
                         str1 = CommonTool.NumToStr(TypeCode.Int32, WBStage.args[0], "D", false);
                         WBStage.mainForm.commandForm.registerControl.SetRegisterValue((string)code.args[2], WBStage.args[0], TypeCode.Int32);
                         break;
                     }
                 case CodeType.DADD:
                 case CodeType.DSUB:
                 case CodeType.DSLLV:
                 case CodeType.DSRLV:
                 case CodeType.DSRAV:
                 case CodeType.DADDI:
                 case CodeType.DSLL:
                 case CodeType.DSRL:
                 case CodeType.DSRA:
                     {
                         str1 = CommonTool.NumToStr(TypeCode.Int64, WBStage.args[0], "D", false);
                         WBStage.mainForm.commandForm.registerControl.SetRegisterValue((string)code.args[2], WBStage.args[0], TypeCode.Int64);
                         break;
                     }
                 case CodeType.ADD_S:
                 case CodeType.SUB_S:
                 case CodeType.MUL_S:
                 case CodeType.DIV_S:
                     {
                         str1 = CommonTool.NumToStr(TypeCode.Single, WBStage.args[0], "D", false);
                         WBStage.mainForm.commandForm.registerControl.SetRegisterValue((string)code.args[2], WBStage.args[0], TypeCode.Single);
                         break;
                     }
                 case CodeType.ADD_D:
                 case CodeType.SUB_D:
                 case CodeType.MUL_D:
                 case CodeType.DIV_D:
                     {
                         str1 = CommonTool.NumToStr(TypeCode.Double, WBStage.args[0], "D", false);
                         WBStage.mainForm.commandForm.registerControl.SetRegisterValue((string)code.args[2], WBStage.args[0], TypeCode.Double);
                         break;
                     }
                 case CodeType.ADDU:
                 case CodeType.SUBU:
                 case CodeType.SLTU:
                 case CodeType.ADDIU:
                 case CodeType.SLTIU:
                     {
                         str1 = CommonTool.NumToStr(TypeCode.UInt32, WBStage.args[0], "D", false);
                         WBStage.mainForm.commandForm.registerControl.SetRegisterValue((string)code.args[2], WBStage.args[0], TypeCode.UInt32);
                         break;
                     }
                 case CodeType.DADDU:
                 case CodeType.DSUBU:
                 case CodeType.DADDIU:
                     {
                         str1 = CommonTool.NumToStr(TypeCode.UInt64, WBStage.args[0], "D", false);
                         WBStage.mainForm.commandForm.registerControl.SetRegisterValue((string)code.args[2], WBStage.args[0], TypeCode.UInt64);
                         break;
                     }
                 case CodeType.BEQZ:
                 case CodeType.BNEZ:
                     {
                         break;
                     }
                 case CodeType.SD:
                 case CodeType.SB:
                 case CodeType.SH:
                 case CodeType.SW:
                 case CodeType.SDC1:
                 case CodeType.SWC1:
                     {
                         break;
                     }
                 case CodeType.LB:
                     {
                         str1 = CommonTool.NumToStr(TypeCode.SByte, WBStage.args[0], "D", false);
                         WBStage.mainForm.commandForm.registerControl.SetRegisterValue((string)code.args[2], WBStage.args[0], TypeCode.SByte);
                         break;
                     }
                 case CodeType.LH:
                     {
                         str1 = CommonTool.NumToStr(TypeCode.Int16, WBStage.args[0], "D", false);
                         WBStage.mainForm.commandForm.registerControl.SetRegisterValue((string)code.args[2], WBStage.args[0], TypeCode.Int16);
                         break;
                     }
                 case CodeType.LW:
                     {
                         str1 = CommonTool.NumToStr(TypeCode.Int32, WBStage.args[0], "D", false);
                         WBStage.mainForm.commandForm.registerControl.SetRegisterValue((string)code.args[2], WBStage.args[0], TypeCode.Int32);
                         break;
                     }
                 case CodeType.LD:
                     {
                         str1 = CommonTool.NumToStr(TypeCode.Int64, WBStage.args[0], "D", false);
                         WBStage.mainForm.commandForm.registerControl.SetRegisterValue((string)code.args[2], WBStage.args[0], TypeCode.Int64);
                         break;
                     }
                 case CodeType.LBU:
                     {
                         str1 = CommonTool.NumToStr(TypeCode.Byte, WBStage.args[0], "D", false);
                         WBStage.mainForm.commandForm.registerControl.SetRegisterValue((string)code.args[2], WBStage.args[0], TypeCode.Byte);
                         break;
                     }
                 case CodeType.LHU:
                     {
                         str1 = CommonTool.NumToStr(TypeCode.UInt16, WBStage.args[0], "D", false);
                         WBStage.mainForm.commandForm.registerControl.SetRegisterValue((string)code.args[2], WBStage.args[0], TypeCode.UInt16);
                         break;
                     }
                 case CodeType.LWU:
                     {
                         str1 = CommonTool.NumToStr(TypeCode.UInt32, WBStage.args[0], "D", false);
                         WBStage.mainForm.commandForm.registerControl.SetRegisterValue((string)code.args[2], WBStage.args[0], TypeCode.UInt32);
                         break;
                     }
                 case CodeType.LDC1:
                     {
                         str1 = CommonTool.NumToStr(TypeCode.Single, WBStage.args[0], "D", false);
                         WBStage.mainForm.commandForm.registerControl.SetRegisterValue((string)code.args[2], WBStage.args[0], TypeCode.Single);
                         break;
                     }
                 case CodeType.LWC1:
                     {
                         str1 = CommonTool.NumToStr(TypeCode.Double, WBStage.args[0], "D", false);
                         WBStage.mainForm.commandForm.registerControl.SetRegisterValue((string)code.args[2], WBStage.args[0], TypeCode.Double);
                         break;
                     }
             }

            IDStage.registerReadManualEvent.Set();

             switch (code.codeType)
             {
                 case CodeType.ADD:
                 case CodeType.SUB:
                 case CodeType.MUL:
                 case CodeType.SLT:
                 case CodeType.AND:
                 case CodeType.NOR:
                 case CodeType.OR:
                 case CodeType.XOR:
                 case CodeType.SLLV:
                 case CodeType.SRAV:
                 case CodeType.SRLV:
                 case CodeType.ADDI:
                 case CodeType.SLTI:
                 case CodeType.ANDI:
                 case CodeType.ORI:
                 case CodeType.XORI:
                 case CodeType.SLL:
                 case CodeType.SRA:
                 case CodeType.SRL:
                 case CodeType.DADD:
                 case CodeType.DSUB:
                 case CodeType.DSLLV:
                 case CodeType.DSRLV:
                 case CodeType.DSRAV:
                 case CodeType.DADDI:
                 case CodeType.DSLL:
                 case CodeType.DSRL:
                 case CodeType.DSRA:
                 case CodeType.ADD_S:
                 case CodeType.SUB_S:
                 case CodeType.MUL_S:
                 case CodeType.DIV_S:
                 case CodeType.ADD_D:
                 case CodeType.SUB_D:
                 case CodeType.MUL_D:
                 case CodeType.DIV_D:
                 case CodeType.ADDU:
                 case CodeType.SUBU:
                 case CodeType.SLTU:
                 case CodeType.ADDIU:
                 case CodeType.SLTIU:
                 case CodeType.DADDU:
                 case CodeType.DSUBU:
                 case CodeType.DADDIU:
                     {
                         Thread thread1 = CommonTool.StartDrawPathsThread(new DrawPaths(
                         new Animate[8] { 
                                CommonTool.SetAnimate(WBStage.position[6],WBStage.position[7],Direction.LeftToRight,(string)code.args[2] +"/" + str1,true,mainForm.GetGraphics(),DrawTool.wbForwadSpanTime),
                                CommonTool.SetAnimate(WBStage.position[7],WBStage.position[4],Direction.BottomToTop,(string)code.args[2] +"/" + str1,true,mainForm.GetGraphics(),DrawTool.wbForwadSpanTime),
                                CommonTool.SetAnimate(WBStage.position[4],WBStage.position[5],Direction.LeftToRight,(string)code.args[2] +"/" + str1,true,mainForm.GetGraphics(),DrawTool.wbForwadSpanTime),
                                CommonTool.SetAnimate(WBStage.position[2],WBStage.position[3],Direction.LeftToRight,(string)code.args[2] +"/" + str1,true,mainForm.GetGraphics(),DrawTool.wbForwadSpanTime),
                                CommonTool.SetAnimate(WBStage.position[3],WBStage.position[11],Direction.TopToBottom,(string)code.args[2] +"/" + str1,true,mainForm.GetGraphics(),DrawTool.wbForwadSpanTime),
                                CommonTool.SetAnimate(WBStage.position[11],IDStage.position[36],Direction.RightToLeft,(string)code.args[2] +"/" + str1,true,mainForm.GetGraphics(),DrawTool.wbForwadSpanTime),
                                CommonTool.SetAnimate(IDStage.position[36],IDStage.position[25],Direction.BottomToTop,(string)code.args[2] +"/" + str1,true,mainForm.GetGraphics(),DrawTool.wbForwadSpanTime),
                                CommonTool.SetAnimate(IDStage.position[25],IDStage.position[26],Direction.LeftToRight,(string)code.args[2] +"/" + str1,true,mainForm.GetGraphics(),DrawTool.wbForwadSpanTime)
                            }, WBStage.mainForm));
                         Thread thread2 = CommonTool.StartDrawPathsThread(new DrawPaths(
                         new Animate[5] { 
                                CommonTool.SetAnimate(WBStage.position[8],WBStage.position[9],Direction.LeftToRight,code.codeType.ToString(),true,mainForm.GetGraphics(),DrawTool.wbForwadSpanTime),
                                CommonTool.SetAnimate(WBStage.position[9],WBStage.position[10],Direction.TopToBottom,code.codeType.ToString(),true,mainForm.GetGraphics(),DrawTool.wbForwadSpanTime),
                                CommonTool.SetAnimate(WBStage.position[10],IDStage.position[35],Direction.RightToLeft,code.codeType.ToString(),true,mainForm.GetGraphics(),DrawTool.wbForwadSpanTime),
                                CommonTool.SetAnimate(IDStage.position[35],IDStage.position[23],Direction.BottomToTop,code.codeType.ToString(),true,mainForm.GetGraphics(),DrawTool.wbForwadSpanTime),
                                CommonTool.SetAnimate(IDStage.position[23],IDStage.position[24],Direction.LeftToRight,code.codeType.ToString(),true,mainForm.GetGraphics(),DrawTool.wbForwadSpanTime)
                            }, WBStage.mainForm));

                         thread1.Join();
                         thread1 = null;
                         thread2.Join();
                         thread2 = null;

                         CommonTool.DrawPath(WBStage.mainForm,
                         new DrawPath[3]{
                                 new DrawPath(mainForm.GetGraphics(),new Point[4]{WBStage.position[6],WBStage.position[7],WBStage.position[4],WBStage.position[5]},DrawTool.orignalPen),
                                 new DrawPath(mainForm.GetGraphics(),new Point[6]{WBStage.position[2],WBStage.position[3],WBStage.position[11],IDStage.position[36],IDStage.position[25],IDStage.position[26]},DrawTool.orignalPen),
                                 new DrawPath(mainForm.GetGraphics(),new Point[6]{WBStage.position[8],WBStage.position[9],WBStage.position[10],IDStage.position[35],IDStage.position[23],IDStage.position[24]},DrawTool.orignalPen)
                            });
                         break;
                     }
                 case CodeType.BEQZ:
                 case CodeType.BNEZ:
                 case CodeType.SD:
                 case CodeType.SB:
                 case CodeType.SH:
                 case CodeType.SW:
                 case CodeType.SDC1:
                 case CodeType.SWC1:
                     {
                         Thread thread1 = CommonTool.StartDrawPathsThread(new DrawPaths(
                         new Animate[5] { 
                                CommonTool.SetAnimate(WBStage.position[8],WBStage.position[9],Direction.LeftToRight,code.codeType.ToString(),true,mainForm.GetGraphics(),DrawTool.wbForwadSpanTime),
                                CommonTool.SetAnimate(WBStage.position[9],WBStage.position[10],Direction.TopToBottom,code.codeType.ToString(),true,mainForm.GetGraphics(),DrawTool.wbForwadSpanTime),
                                CommonTool.SetAnimate(WBStage.position[10],IDStage.position[35],Direction.RightToLeft,code.codeType.ToString(),true,mainForm.GetGraphics(),DrawTool.wbForwadSpanTime),
                                CommonTool.SetAnimate(IDStage.position[35],IDStage.position[23],Direction.BottomToTop,code.codeType.ToString(),true,mainForm.GetGraphics(),DrawTool.wbForwadSpanTime),
                                CommonTool.SetAnimate(IDStage.position[23],IDStage.position[24],Direction.LeftToRight,code.codeType.ToString(),true,mainForm.GetGraphics(),DrawTool.wbForwadSpanTime)
                            }, WBStage.mainForm));
                         thread1.Join();
                         thread1 = null;

                         CommonTool.DrawPath(WBStage.mainForm,
                         new DrawPath[1]{
                                 new DrawPath(mainForm.GetGraphics(),new Point[6]{WBStage.position[8],WBStage.position[9],WBStage.position[10],IDStage.position[35],IDStage.position[23],IDStage.position[24]},DrawTool.orignalPen)
                            });
                         break;
                     }
                 case CodeType.LB:
                 case CodeType.LH:
                 case CodeType.LW:
                 case CodeType.LD:
                 case CodeType.LBU:
                 case CodeType.LHU:
                 case CodeType.LWU:
                 case CodeType.LDC1:
                 case CodeType.LWC1:
                     {
                         Thread thread1 = CommonTool.StartDrawPathsThread(new DrawPaths(
                         new Animate[6] { 
                                CommonTool.SetAnimate(WBStage.position[0],WBStage.position[1],Direction.LeftToRight,(string)code.args[2] +"/" + str1,true,mainForm.GetGraphics(),DrawTool.wbForwadSpanTime),
                                CommonTool.SetAnimate(WBStage.position[2],WBStage.position[3],Direction.LeftToRight,(string)code.args[2] +"/" + str1,true,mainForm.GetGraphics(),DrawTool.wbForwadSpanTime),
                                CommonTool.SetAnimate(WBStage.position[3],WBStage.position[11],Direction.TopToBottom,(string)code.args[2] +"/" + str1,true,mainForm.GetGraphics(),DrawTool.wbForwadSpanTime),
                                CommonTool.SetAnimate(WBStage.position[11],IDStage.position[36],Direction.RightToLeft,(string)code.args[2] +"/" + str1,true,mainForm.GetGraphics(),DrawTool.wbForwadSpanTime),
                                CommonTool.SetAnimate(IDStage.position[36],IDStage.position[25],Direction.BottomToTop,(string)code.args[2] +"/" + str1,true,mainForm.GetGraphics(),DrawTool.wbForwadSpanTime),
                                CommonTool.SetAnimate(IDStage.position[25],IDStage.position[26],Direction.LeftToRight,(string)code.args[2] +"/" + str1,true,mainForm.GetGraphics(),DrawTool.wbForwadSpanTime)
                            }, WBStage.mainForm));
                         Thread thread2 = CommonTool.StartDrawPathsThread(new DrawPaths(
                         new Animate[5] { 
                                CommonTool.SetAnimate(WBStage.position[8],WBStage.position[9],Direction.LeftToRight,code.codeType.ToString(),true,mainForm.GetGraphics(),DrawTool.wbForwadSpanTime),
                                CommonTool.SetAnimate(WBStage.position[9],WBStage.position[10],Direction.TopToBottom,code.codeType.ToString(),true,mainForm.GetGraphics(),DrawTool.wbForwadSpanTime),
                                CommonTool.SetAnimate(WBStage.position[10],IDStage.position[35],Direction.RightToLeft,code.codeType.ToString(),true,mainForm.GetGraphics(),DrawTool.wbForwadSpanTime),
                                CommonTool.SetAnimate(IDStage.position[35],IDStage.position[23],Direction.BottomToTop,code.codeType.ToString(),true,mainForm.GetGraphics(),DrawTool.wbForwadSpanTime),
                                CommonTool.SetAnimate(IDStage.position[23],IDStage.position[24],Direction.LeftToRight,code.codeType.ToString(),true,mainForm.GetGraphics(),DrawTool.wbForwadSpanTime)
                            }, WBStage.mainForm));

                         thread1.Join();
                         thread1 = null;
                         thread2.Join();
                         thread2 = null;

                         CommonTool.DrawPath(WBStage.mainForm,
                         new DrawPath[3]{
                                 new DrawPath(mainForm.GetGraphics(),new Point[2]{WBStage.position[0],WBStage.position[1]},DrawTool.orignalPen),
                                 new DrawPath(mainForm.GetGraphics(),new Point[6]{WBStage.position[2],WBStage.position[3],WBStage.position[11],IDStage.position[36],IDStage.position[25],IDStage.position[26]},DrawTool.orignalPen),
                                 new DrawPath(mainForm.GetGraphics(),new Point[6]{WBStage.position[8],WBStage.position[9],WBStage.position[10],IDStage.position[35],IDStage.position[23],IDStage.position[24]},DrawTool.orignalPen)
                            });
                         break;
                     }
             }
             IDStage.idDrawManualEvent.Set();

             manuaEevent.Set();
        }

        static public void Start(MainForm param)
        {
            mainForm = param;
            //开始标志
            manuaEevent.Reset();
            wbThread = new Thread(new ThreadStart(ThreadFun));
            wbThread.Start();
        }

        static public void Initialize()
        {
            WBStage.enableRun = -1;
            manuaEevent = new ManualResetEvent(false);
        }

        static public void Wait()
        {
            manuaEevent.WaitOne();
        }

        static public void Close()
        {
            if (wbThread != null && wbThread.IsAlive)
            {
                wbThread.Join();
            }
        }
    }
}
